﻿//#define WMTHEIGHT_MAP
#define ROAD_DEBUG

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using Random = UnityEngine.Random;

namespace WorldMapTools
{

    [DisallowMultipleComponent]
    public class CityGen
    {
        //標(*)為重要參數

        //-----------------------------------------------邊界
        const float minBound = 0.0000f;
        const float maxBound = 0.9999f;
        //-----------------------------------------------

        //-----------------------------------------------初始關卡公路長度控制J
        int STARTROADWIDTH = 40;//基本長度
        int START_JITTER_LENGTH = 20;//JITTER隨機抖動長度
        //-----------------------------------------------

        //-----------------------------------------------//路口合并掃描，會在【-WIDTH，+WIDTH】正方形距離内掃描最近的路口並產生合并，距離越大，交叉路口會更容易合并在一起(*)
        int INTERSECTION_SCAN_WIDTH_A = 10;//A型(*)
        int INTERSECTION_SCAN_WIDTH_B = 5;//B型(*)
        int INTERSECTION_SCAN_WIDTH_C = 5;//C型(*)
        //-----------------------------------------------

        //-----------------------------------------------公路生長時的^長度^控制J(*)
        //高速公路A 長度控制
        float ROAD_LENGTH_HIGHWAY_0 = 0.04f;//(*)
        float ROAD_LENGTH_MAJOR_0 = 0.04f;//(*)
        float ROAD_LENGTH_MINOR_0 = 0.04f;//(*)
        float ROAD_LENGTH_JITTER_0 = 0.02f;// (*)
        float HIGHWAY_ANGLE_JITTER_0 = 0.82999f;//A型生長方向抖動(*)

        //細分公路B 長度控制
        float ROAD_LENGTH_HIGHWAY_1 = 0.025f;//沿原方向生長基量(*)
        float ROAD_LENGTH_MAJOR_1 = 0.025f;//沿側枝90°垂直生長基量，B(*)
        float ROAD_LENGTH_MINOR_1 = 0.025f;//沿側枝90°垂直生長基量，C(*)
        float ROAD_LENGTH_JITTER_1 = 0.000f;//B型生長長度抖動(*)
        float HIGHWAY_ANGLE_JITTER_1 = 0.1999f;//B型生長方向抖動(*)

        //細分公路C 長度控制
        float ROAD_LENGTH_MAJOR_2 = 0.025f;//0.0125f;(*)
        float ROAD_LENGTH_MINOR_2 = 0.025f;//0.0125f;(*)
        float ROAD_LENGTH_JITTER_2 = 0.000f;//(*)
        //-----------------------------------------------



        //-----------------------------------------------公路生長時的^方向^抖動控制J
        float HIGHWAY_PROMOTION_PROBABILITY = 0.2f;//A型公路90度側向生長概率(*)
        float SIDE_ROAD_PROBABILITY = 0.5f;//C型90度側枝概率(*)

        float GRID_DEVIATION_PROBABILITY_0 = 0.05f;//A概率
        float GRID_DEVIATION_AMOUNT_0 = 1.46f;//A抖動MAX量

        float GRID_DEVIATION_PROBABILITY_1 = 0.2f;//B概率
        float GRID_DEVIATION_AMOUNT_1 = 1.46f;//B抖動MAX量

        float GRID_DEVIATION_PROBABILITY_2 = 0.2f;//C概率
        float GRID_DEVIATION_AMOUNT_2 = 1.46f;//C抖動MAX量

        float WEIGHT_TERRAIN_CONTOUR = 0.0f;//公路直向生長方向改變概率基值
        float WEIGHT_TERRAIN_CONTOUR_JITTER = 0.5f;//公路直向生長方向改變抖動
        //-----------------------------------------------


        //-----------------------------------------------生長所有的約束結果即 公路修建耗損資源為cost ^<0.0f,1.0f>,在算出所有約束結果cost時，對cost結果根據閾值隨機篩選是否繼續修建
        float COST_THRESHOLD = 0.5f;//基本cost閾值
        float COST_THRESHOLD_JITTER = 0.2f;//cost閾值抖動  -> 【COST_THRESHOLD - COST_THRESHOLD_JITTER ， COST_THRESHOLD + COST_THRESHOLD_JITTER】
        //-----------------------------------------------

        //-----------------------------------------------十字路口過載/欠載時 通過約束的閾值，越大越不容易產生過載/欠載
        float COST_INTERSECIONT_OVERLOARD = 0.25f;//(*)
        float COST_INTERSECIONT_UNDERLOAD = 0.00f;
        //-----------------------------------------------

        //-----------------------------------------------//兩條邊夾角dot點機最大值
        float INTERSECIONT_DOT_01 = 0.92f;//(*)
        float INTERSECIONT_DOT_10 = 0.45f;//(*)
        //-----------------------------------------------
#if WMTHEIGHT_MAP
        const float NUM_HIGHWAY_PROBES = 10;//根據圖來 圓周采樣生長點附近高度
        const float ANGLE_HIGHWAY_PROBES = 0.8f;
#endif
        //const float HIGHWAY_PROBE_JITTER = 0.2999f;

        const float EVAL_DELAY_HIGHWAY = 1.0f;//優先級A(固定)
        const float EVAL_DELAY_MAJOR = 10.0f;//優先級B(固定)
        const float EVAL_DELAY_MINOR = 50.0f;//優先級C(固定)

        private Color[] pixR;

        public int _Width = 1200;//高度
        public int _Height = 1200;//寬度

        public Texture2D cityTex;
        public Texture2D kcityTex
        {
            get
            {
                if (cityTex == null)
                {
                    cityTex = new Texture2D(_Width, _Height);
                }

                return cityTex;
            }
            set
            {
                cityTex = value;
            }
        }

        public void SetGUI()
        {
            kcityTex.SetPixels(pixR);
            kcityTex.Apply();
        }

        static string lastPath = @"\Scripts\Tools\Maptools\Editor\Config.txt";

        public void OpenConfig()
        {
            string path = Application.dataPath + lastPath;
            try
            {
                path = path.Replace("/", "\\");
                System.Diagnostics.Process.Start("explorer.exe", path);
            }
            catch { }
        }

        public void ImportTxtConfig()
        {

            try
            {
                //string path = EditorUtility.OpenFilePanel("打開", "", "txt");
                string path = Application.dataPath + lastPath;

                if (!string.IsNullOrEmpty(path))
                {
                    if (File.Exists(path))
                    {
                        using (StreamReader sr = new StreamReader(path))
                        {
                            while (sr.Peek() >= 0)
                            {
                                string line = sr.ReadLine();
                                int _ConfigBegin = line.IndexOf('[');
                                int _ConfigEnd = line.LastIndexOf(']');
                                if (_ConfigEnd <= _ConfigBegin)
                                    continue;

                                string configLine = line.Substring(_ConfigBegin + 1, _ConfigEnd - _ConfigBegin - 1);
                                configLine = configLine.Replace(" ","");
                                int _Sign = configLine.LastIndexOf('=');
                                string _name = configLine.Substring(0, _Sign);
                                string _value = configLine.Substring(_Sign + 1, configLine.Length - _Sign - 1);
                                float.TryParse(_value,out float _CompareValue);

                                string _replaceZero = _value.Replace("0","");
                                bool _NotZero = _replaceZero.Equals("") || _replaceZero.Equals(".");

                                if (!_CompareValue.ToString().Equals(_value) && !_NotZero)
                                    continue;

                                ConfigMapping(_name, _CompareValue);
                            }
#if ROAD_DEBUG
                            Debug.Log("配置導入成功!");
#endif
                        }

                    }
                }
            }
            catch { }
        }


        public Texture2D kcurve;
        public IEnumerator ImportPNG()
        {
            string path = EditorUtility.OpenFilePanel("打開", "", "png");

            if (!string.IsNullOrEmpty(path))
            {
                UnityWebRequest request = UnityWebRequest.Get(@"file://" + path);
                DownloadHandlerTexture texture = new DownloadHandlerTexture(true);
                request.downloadHandler = texture;
                yield return request.SendWebRequest();
                if (!request.isNetworkError)
                {
                    kcurve = texture.texture;
                    if (kcurve != null)
                    {
                        kcurve.wrapMode = TextureWrapMode.Clamp;
                    }
                }
            }

            BeginWithPicture();
#if ROAD_DEBUG
            Debug.Log("關卡點已刷新:" + startPots.Count + "個.");
#endif
        }

        public void ExportPNG()
        {
            string path = EditorUtility.SaveFilePanel("保存", "", "", "png");
            if (kcityTex != null && !string.IsNullOrEmpty(path))
            {
                byte[] buffer = kcityTex.EncodeToPNG();
                System.IO.File.WriteAllBytes(path, buffer);

                path = FileUtil.GetProjectRelativePath(path);
                if (string.IsNullOrEmpty(path) == false)
                    AssetDatabase.ImportAsset(path);
            }
        }

        public struct StartPot
        {
            public Vector2 core;
            public Vector2 spot;
            public Vector2 spot2;
            public Vector2 norm;
        }

        private List<StartPot> startPots;
        public void BeginWithPicture()
        {
            if (kcurve == null)
                return;

            startPots = new List<StartPot>();

            Color[] col = kcurve.GetPixels();

            mountain = new int[_Height, _Width];


            for (int j = 0; j < kcurve.height; j++)
            {
                for (int i = 0; i < kcurve.width; i++)
                {
                    int index = j * kcurve.width + i;
                    if (col[index].r >= 0.9f)
                    {
                        StartPot spot = new StartPot();
                        spot.spot.x = i;
                        spot.spot.y = j;

                        for (int dj = -20; dj < 21; dj++)
                        {
                            bool find = false;
                            for (int di = -20; di < 21; di++)
                            {
                                int ddj = j + dj;
                                int ddi = i + di;
                                int ddindex = ddj * kcurve.width + ddi;
                                if (ddindex > -1 && ddindex < col.Length)
                                {
                                    if (col[ddindex].b > 0.9f)
                                    {
                                        spot.norm.x = -dj;
                                        spot.norm.y = di;
                                        spot.norm.Normalize();

                                        spot.core.x = spot.spot.x;
                                        spot.core.y = spot.spot.y;

                                        spot.spot2 = spot.spot + (spot.norm * 0.5f * jitter(STARTROADWIDTH, START_JITTER_LENGTH));
                                        spot.spot -= (spot.norm * 0.5f * jitter(STARTROADWIDTH, START_JITTER_LENGTH));
                                        spot.spot2.x = (spot.spot2.x / kcurve.width);
                                        spot.spot2.y = (spot.spot2.y / kcurve.height);
                                        spot.spot.x = (spot.spot.x / kcurve.width);
                                        spot.spot.y = (spot.spot.y / kcurve.height);
                                        spot.core.x = (spot.core.x / kcurve.width);
                                        spot.core.y = (spot.core.y / kcurve.height);

                                        startPots.Add(spot);
                                        find = true;
                                        break;
                                    }
                                }
                            }
                            if (find)
                                break;
                        }
                    }
                    else if (col[index].b >= 0.9f)
                    {
                        int px = (int)(i * (kcurve.width / (float)_Width));
                        int py = (int)(j * (kcurve.height / (float)_Height));
                        mountain[py, px] = int.MaxValue;
                    }
                }
            }
        }

        List<Vertex> startTxtPots;
        List<Edge> startTxtEdges;

        public void ImportTxt()
        {
            startTxtPots = new List<Vertex>();
            startTxtEdges = new List<Edge>();

            try
            {
                string path = EditorUtility.OpenFilePanel("打開", "", "txt");
                if (!string.IsNullOrEmpty(path))
                {
                    if (File.Exists(path))
                    {
                        using (StreamReader sr = new StreamReader(path))
                        {
                            bool vectorState = true;
                            while (sr.Peek() >= 0)
                            {
                                string line = sr.ReadLine();
                                string[] points = line.Split(',');
                                if (vectorState)
                                {
                                    float x = 0, y = 0;
                                    if (points.Length >= 2)
                                    {
                                        float.TryParse(points[0], out x);
                                        float.TryParse(points[1], out y);
                                        if (x == _Width)
                                            x--;
                                        if (y == _Height)
                                            y--;

                                        x = (x / _Width);
                                        y = (y / _Height);
                                    }
                                    Vertex vertex = new Vertex(x, y);
                                    vertex.index = startTxtPots.Count;
                                    startTxtPots.Add(vertex);

                                    if (line.Equals(""))
                                        vectorState = false;
                                }
                                else
                                {
                                    int x = 0, y = 0;
                                    if (points.Length >= 2)
                                    {
                                        int.TryParse(points[0], out x);
                                        int.TryParse(points[1], out y);
                                        x -= 1;
                                        y -= 1;
                                        Edge edge = new Edge(0);
                                        edge.v[0] = x;
                                        edge.v[1] = y;
                                        edge.index = startTxtEdges.Count;
                                        edge.alive = true;
                                        startTxtEdges.Add(edge);
                                    }
                                }
                            }
                        }

#if ROAD_DEBUG
                        Debug.Log("導入頂點：" + startTxtPots.Count);
                        Debug.Log("導入邊：" + startTxtEdges.Count);
#endif
                    }
                    else
                    {
                    }
                }
            }
            catch { }
        }

        public void Generate()
        {

            pixR = new Color[kcityTex.width * kcityTex.height];

            CityLSystemGenerator();

            SetGUI();
        }


        //return 0-1
        public float GetRandom()
        {
            return (Random.Range(0, float.MaxValue) / float.MaxValue);
        }

        //return float between c-r, c+r
        public float jitter(float c, float r)
        {
            float x = (2 * GetRandom() - 1.0f) * r;// [-r,r]
            return c + x;
        }

        public enum RoadType
        {
            Axiom = 0,//起始道路
            HightWay = 1,//主幹道
            Major = 2,//主幹道側枝
            Minor = 3,//主幹道側枝側枝
            Null = 4,//初始化
        }

        public class Vertex
        {
            public float x;//坐標
            public float y;//坐標
            public float z;//坐標
            public int index;//序號
            public RoadType type;

            public List<int> adjacent;//鄰接點
            public Vertex(float x, float y, float z = 0)
            {
                this.x = x;
                this.y = y;
                this.z = z;
                adjacent = new List<int>();
                index = -1;

                type = RoadType.Null;
            }

            //為當前頂點添加一個鄰接頂點
            public void AddAdjacent(int adInx)
            {
                if (!adjacent.Contains(adInx))
                    adjacent.Add(adInx);
            }

            //為當前頂點移除一個鄰接頂點
            public void RemoveAdjacent(int adInx)
            {
                if (adjacent.Contains(adInx))
                    adjacent.Remove(adInx);
            }

            public bool ExistAdjacent(int adInx)
            {
                return adjacent.Contains(adInx);
            }

            public static Vertex operator +(Vertex B, Vertex C)
            {
                return new Vertex(B.x + C.x, B.y + C.y);
            }

            public static Vertex operator -(Vertex B, Vertex C)
            {
                return new Vertex(B.x - C.x, B.y - C.y);
            }

            public Vertex Normalized2d()
            {
                float len = Mathf.Sqrt(x * x + y * y);
                x /= len;
                y /= len;
                return this;
            }

        }

        public class Attri
        {
            public RoadType type;
            public float angle;//主幹道方向
            public float axis;

            public bool isSnapToAdj;

            public Attri(float t)
            {
                type = RoadType.Axiom;
                angle = 0;
                axis = 0;
                isSnapToAdj = false;
            }
        }

        public class Edge
        {
            public bool alive;//當前邊是否有效

            public int index;//索引
            public float t;//優先度
            public int[] v;//兩端點序列
            public Attri attri;//路屬性
            public Vector3[] newVertices;//未來將要產生的規劃點位置

            public bool splitRoad;//主動截斷
            public bool extendRoad;//主動延長

            public int spexTarget;//被動截斷延長對象的索引
            public bool beSplitedL;//被動左截斷
            public bool beSplitedR;//被動右截斷
            public Edge(float t)
            {
                v = new int[2];
                v[0] = -1;
                v[1] = -1;
                this.t = t;
                attri = new Attri(0);
                newVertices = new Vector3[2];
                splitRoad = false;
                extendRoad = false;
                index = -1;

                spexTarget = -1;
                alive = false;
                beSplitedL = false;
                beSplitedR = false;
            }
            public Edge(int t0, int t1)
            {
                v = new int[2];
                v[0] = t0;
                v[1] = t1;
                this.t = 0;
                attri = new Attri(0);
                newVertices = new Vector3[2];
                splitRoad = false;
                extendRoad = false;
                index = -1;

                spexTarget = -1;
                alive = false;
                beSplitedL = false;
                beSplitedR = false;
            }
            public Edge(float t, RoadType type, float angle, float axis, int i0, float x, float y)
            {
                this.t = t;
                splitRoad = false;
                extendRoad = false;
                attri = new Attri(0);
                attri.type = type;
                attri.angle = angle;
                attri.axis = axis;

                //標記實體A
                v = new int[2];
                v[0] = i0;//實體A
                v[1] = -1;//幻肢B

                //標記幻肢B
                newVertices = new Vector3[2];
                newVertices[1].x = x;
                newVertices[1].y = y;
                newVertices[1].z = 0;
                index = -1;

                spexTarget = -1;
                alive = false;
                beSplitedL = false;
                beSplitedR = false;
            }

            public Edge(Edge c)
            {
                t = c.t;
                splitRoad = c.splitRoad;
                extendRoad = c.extendRoad;
                attri = new Attri(0);
                attri.type = c.attri.type;
                attri.angle = c.attri.angle;
                attri.axis = c.attri.axis;

                //標記實體A
                v = new int[2];
                v[0] = c.v[0];//實體A
                v[1] = c.v[1];//幻肢B

                newVertices = new Vector3[2];
                newVertices[1].x = c.newVertices[1].x;
                newVertices[1].y = c.newVertices[1].y;
                newVertices[1].z = c.newVertices[1].z;

                index = c.index;
                spexTarget = c.spexTarget;
                alive = c.alive;
                beSplitedL = false;
                beSplitedR = false;
            }
        }


        //--------------------------------------------------------L排序

        //優先級小頂堆
        class Prority_Heap
        {
            //List<Edge> elements;
            Edge[] elements;
            public int count;
            public Prority_Heap()
            {
                elements = new Edge[64000];
                count = 0;
            }


            //移除堆頂操作pop
            public void Pop()
            {
                elements[1] = elements[count];
                count--;

                int top = 1;

                int level = (int)(Mathf.Log(count, 2)) + 1;
                for (int i = 1; i < level; i++)
                {
                    int sonL = top * 2;
                    int sonR = top * 2 + 1;
                    //和左右兩孩子都進行比較
                    if (sonR <= count)
                    {

                        int ex = elements[sonR].t <= elements[sonL].t ? sonR : sonL;
                        if (elements[top].t >= elements[ex].t)
                        {
                            Edge temp = elements[ex];
                            elements[ex] = elements[top];
                            elements[top] = temp;
                            top = ex;
                        }
                    }
                    else if (sonL <= count) //和左孩子都進行比較
                    {
                        if (elements[top].t >= elements[sonL].t)
                        {
                            Edge temp = elements[sonL];
                            elements[sonL] = elements[top];
                            elements[top] = temp;
                            top = sonL;
                        }
                    }
                }

            }

            //加入隊尾操作push
            public void push(Edge node)
            {
                count++;
                elements[count] = node;

                int bottom = count;

                int level = (int)(Mathf.Log(count, 2)) + 1;
                for (int i = 1; i < level; i++)
                {
                    int parent = (bottom / 2);
                    if (parent > 0)
                    {
                        if (elements[bottom].t < elements[parent].t)
                        {
                            Edge temp = elements[bottom];
                            elements[bottom] = elements[parent];
                            elements[parent] = temp;
                            bottom = parent;
                        }
                    }
                }
            }

            //取出堆頂
            public Edge Top()
            {
                return elements[1];
            }

        }

        //Edge排序類(按t)
        class SortedEdges
        {
            public int index;
            Prority_Heap procesedEdges;

            public SortedEdges()
            {
                index = 0;
                procesedEdges = new Prority_Heap();
            }

            //按優先度t插入排序表中
            public void Push(Edge e)
            {
                e.index = ++index;
                procesedEdges.push(e);
            }

            //推出最小t
            public void Pop()
            {
                procesedEdges.Pop();
            }


            public Edge Top()
            {

                return procesedEdges.Top();
            }

            public int Count()
            {
                return procesedEdges.count;
            }
        }
        //--------------------------------------------------------

        //--------------------------------------------------------碰撞檢測
        private int[,] mountain;//山體2D碰撞
        private int[,] eContainer;//邊2D碰撞
        private int[,] vContainer;//頂點2D碰撞


        private int _cHeight;
        private int _cWidth;
        public void InitCollider()
        {
            _cHeight = _Height / 2;
            _cWidth = _Width / 2;

            vContainer = new int[_cHeight, _cWidth];
            eContainer = new int[_Height, _Width];

            for (int j = 0; j < _cHeight; j++)
            {
                for (int i = 0; i < _cWidth; i++)
                {
                    vContainer[j, i] = -1;
                }
            }

            for (int j = 0; j < _Height; j++)
            {
                for (int i = 0; i < _Width; i++)
                {
                    eContainer[j, i] = -1;
                }
            }
        }

        public void ColliderAdd(float x, float y)
        {
            vContainer[(int)(y * _cHeight), (int)(x * _cWidth)] = 1;
        }

        //加入一頂點作爲邊碰撞檢測數據
        public void ColliderAdd(Vertex v)
        {
            vContainer[(int)(v.y * _cHeight), (int)(v.x * _cWidth)] = v.index;
        }

        //const float NEAR_THRESHOLD = 25.0f;

        public int ColliderFindNearby(Vertex v, int i0,int times)
        {
            //const int times = 10;

            int x = (int)(v.x * _cWidth);
            int y = (int)(v.y * _cHeight);

            float minDis = float.MaxValue;
            int minIndex = -1;

            for (int j = y - times; j <= y + times; j++)
            {
                for (int i = x - times; i <= x + times; i++)
                {
                    if (j > -1 && j < _cHeight && i > -1 && i < _cWidth)
                    {
                        int r = vContainer[j, i];
                        if (r > -1 && r != i0)
                        {
                            float dis = i * i + j * j;
                            if (dis < minDis)//&& (int)(v.type) <= (int)(GetVertex(r).type)
                            {
                                minDis = dis;
                                minIndex = r;
                            }
                        }
                    }
                }
            }

            //if (minDis > NEAR_THRESHOLD)
            //    minIndex = -1;

            return minIndex;
        }


        //--------------------------------------------------------
        //加入一條邊作爲邊碰撞檢測數據
        public void ColliderAddRemove(Edge e, bool add = true)
        {
            Vertex p1, p2;

            if (e.v[0] > -1)
                p1 = GetVertex(e.v[0]);
            else
            {
                p1 = new Vertex(e.newVertices[0].x, e.newVertices[0].y);
            }

            if (e.v[1] > -1)
                p2 = GetVertex(e.v[1]);
            else
            {
                p2 = new Vertex(e.newVertices[1].x, e.newVertices[1].y);
            }

            float dx = (p2.x - p1.x) * _Width;
            float dy = (p2.y - p1.y) * _Height;

            float len = Mathf.Sqrt(dx * dx + dy * dy);

            float ddx = dx / len;
            float ddy = dy / len;

            float px = p1.x * _Width;
            float py = p1.y * _Height;

            for (int i = 0; i < len; i++)
            {
                int ry = (int)(py + ddy * i);
                int rx = (int)(px + ddx * i);

                if (ry < 0 || ry >= _Height || rx < 0 || rx >= _Width)
                    continue;
                if (add)
                    eContainer[ry, rx] = e.index;//從0開始，-1作爲空
                else
                {
                    //如果是移除操作的話，移除所有當前邊的碰撞
                    if (eContainer[ry, rx] == e.index)
                        eContainer[ry, rx] = -1;
                }
            }
        }

        public float ColliderFindIntersection(Vertex p1, Vertex p2, Edge e)
        {
            const int overFind = 10;
            float cost = 0;

            float dx = (p2.x - p1.x) * _Width;
            float dy = (p2.y - p1.y) * _Height;
            float len = Mathf.Sqrt(dx * dx + dy * dy);
            float ddx = dx / len;
            float ddy = dy / len;
            float px = p1.x * _Width;
            float py = p1.y * _Height;

            int overDistance = int.MaxValue;
            int r0 = eContainer[(int)py, (int)px];

            for (int i = 0; i < len + overFind; i++)
            {
                int ry = (int)(py + ddy * i);
                int rx = (int)(px + ddx * i);

                if (ry < 0 || ry >= _Height || rx < 0 || rx >= _Width)
                    continue;

                int r = eContainer[ry, rx];//從0開始，-1作爲空
                int m = 0;
                if (mountain != null)
                {
                    m = mountain[ry, rx];
                    if (m > 0)
                    {
                        return 1.0f;//被山阻擋
                    }
                }

                if (r > -1 && r != r0)
                {
                    overDistance = (int)len - i;

                    if (overDistance >= 0)//邊過長，需要剪短Snap
                    {
                        e.newVertices[1].x = rx / (float)_Width;
                        e.newVertices[1].y = ry / (float)_Height;
                        e.splitRoad = true;
                        e.spexTarget = r;

                        //float _cost = Mathf.Abs(((float)(overDistance)) / _Height);
                        if (overDistance > len * 0.75f)
                            cost = 1.0f;
                        break;
                    }
                    else//邊過短，需要延長
                    {
                        e.newVertices[1].x = rx / (float)_Width;
                        e.newVertices[1].y = ry / (float)_Height;
                        e.extendRoad = true;
                        e.spexTarget = r;

                        //float _cost = Mathf.Abs(((float)(overDistance)) / _Height);
                        if (overDistance > len * 0.75f)
                            cost = 1.0f;

                        break;
                    }
                }
            }
            return cost;
        }

        //--------------------------------------------------------

        private List<Vertex> vertices;//<<<<<<<<<<<<<<<<<<<<<<<<結果數據>>>>>>>>>>>>>>>>>>>>>>>>所有生成的端點
        private List<Edge> edges;     //<<<<<<<<<<<<<<<<<<<<<<<<結果數據>>>>>>>>>>>>>>>>>>>>>>>>所有生成的邊

        private SortedEdges procesedEdges;//進行中的公路數據
        private float MIN_DIST;

        public Vertex GetVertex(int index)
        {
            return vertices[index];
        }

        public int GetVertexCount()
        {
            return vertices.Count;
        }
        public void AddVertex(Vertex tar)
        {
            tar.index = vertices.Count;
            vertices.Add(tar);
            ColliderAdd(tar);
        }
        public void RemoveVertex(Vertex tar)
        {
            int index = vertices.IndexOf(tar);
#if ROAD_DEBUG
            if (index == -1)
            {
                Debug.Log("RemoveVertex , 不存在被移除頂點，移除操作失敗!");
            }
            else if (index != vertices.Count - 1)
                Debug.Log("RemoveVertex , 移除頂點非新添加頂點!!!");
#endif

            if (index > -1 && index == vertices.Count - 1)
                vertices.Remove(tar);
        }

        public void RemoveVertex(int index)
        {
            if (index > -1 && index < vertices.Count)
                vertices.RemoveAt(index);
        }

        public void AddEdge(Edge e)
        {
            Edge findE = edges.Find(t => t.v[0] == e.v[0] && t.v[1] == e.v[1]);

            if (findE != null)
            {
#if ROAD_DEBUG
                Debug.Log("AddEdge() -> findE , 添加了一條已存在的邊.");
#endif
                findE.alive = true;
            }
            else
            {
                e.alive = true;
                e.index = edges.Count;
                edges.Add(e);
                findE = e;
            }
            //為當前頂點添加一個鄰接頂點
            GetVertex(findE.v[0]).AddAdjacent(findE.v[1]);
            GetVertex(findE.v[1]).AddAdjacent(findE.v[0]);

            ColliderAddRemove(findE);
        }

        public void RemoveEdge(Edge e)
        {
            e.alive = false;

            //為當前頂點添加一個鄰接頂點
            GetVertex(e.v[0]).RemoveAdjacent(e.v[1]);
            GetVertex(e.v[1]).RemoveAdjacent(e.v[0]);

            ColliderAddRemove(e, false);//移除碰撞
        }

        public Edge GetEdge(int index)
        {
            return edges[index];
        }


        //----------------------------------------主函數
        public void CityLSystemGenerator()
        {
            DateTime sDateTime = DateTime.Now;

            ImportTxtConfig();//讀取生成配置
            // int[,] map = new int[_Height, _Width];
            InitCollider();

            MIN_DIST = (1.0f / _Width);

            procesedEdges = new SortedEdges();
            vertices = new List<Vertex>();
            edges = new List<Edge>();

            //使用text讀入的一級道路數據
            if (startTxtPots != null && startTxtEdges != null)
            {
                for (int z = 0; z < startTxtPots.Count; z++)
                {
                    startTxtPots[z].adjacent.Clear();
                    vertices.Add(startTxtPots[z]);
                    ColliderAdd(startTxtPots[z]);
                }
                for (int z = 0; z < startTxtEdges.Count; z++)
                {
                    edges.Add(startTxtEdges[z]);
                    ColliderAddRemove(startTxtEdges[z]);
                }
            }

            float t = 0;
            Vertex sP, sP2; Edge startEdge;

            //使用png讀入的關卡點初始生長點數據
            if (startPots != null)
            {
                for (int k = 0; k < startPots.Count; k++)
                {
                    StartPot pot = startPots[k];
                    sP = new Vertex(pot.spot.x, pot.spot.y);
                    sP2 = new Vertex(pot.spot2.x, pot.spot2.y);
                    sP.type = RoadType.HightWay;
                    sP2.type = RoadType.HightWay;
                    AddVertex(sP);
                    AddVertex(sP2);

                    startEdge = new Edge(t);

                    startEdge.v[0] = sP.index;
                    startEdge.v[1] = sP2.index;
                    procesedEdges.Push(startEdge);
                }
            }
            else
            {
                sP = new Vertex(GetRandom(), GetRandom());
                sP2 = new Vertex(sP.x + MIN_DIST * 5, sP.y);

                sP.type = RoadType.HightWay;
                sP2.type = RoadType.HightWay;
                AddVertex(sP);
                AddVertex(sP2);

                startEdge = new Edge(t);
                startEdge.v[0] = sP.index;
                startEdge.v[1] = sP2.index;

                procesedEdges.Push(startEdge);
            }

            //----------------------------------------主循環
            int i = 0;
            while (procesedEdges.Count() > 0)
            {
                Edge pEdge = procesedEdges.Top();//彈出最高優先級待處理路段
                procesedEdges.Pop();

                bool accept = LocalConstraint(pEdge);
                if (accept)
                {
                    int i0, i1;
                    if (AcceptProposal(pEdge, out i0, out i1))//處理當前路段
                        GlobleGoals(pEdge.t, pEdge, i0, i1);//根據處理後的路段延展出分支
                }

                i++;
                if(i>10000)
                    break;
            }
            //----------------------------------------


            //----------------------------------------畫出結果數據
            Draw();//畫出路段
            Debug.LogFormat("生成路段數: "+ edges.Count + " .耗時：{0}ms", (int)(DateTime.Now - sDateTime).TotalMilliseconds);
        }



        public void Step()
        {
            if (procesedEdges == null)
                return;

            int i = 0;
            while (procesedEdges.Count() > 0)
            {
                Edge pEdge = procesedEdges.Top();
                procesedEdges.Pop();

                bool accept = LocalConstraint(pEdge);
                if (accept)
                {
                    int i0, i1;
                    if (AcceptProposal(pEdge, out i0, out i1))
                        GlobleGoals(pEdge.t, pEdge, i0, i1);
                }
                i++;
                if (i > 0)
                    break;
            }

            Draw();
            SetGUI();

        }

        public void Draw()
        {
            ModelGeneratorUtility.InitPrefab();

            //mountain
            if (mountain != null)
            {
                for (int j = 0; j < _Height; j++)
                {
                    for (int i = 0; i < _Width; i++)
                    {
                        if (mountain[j, i] > 0)
                        {
                            DrawVertex(new Vertex(i / (float)_Width, j / (float)_Height), Color.blue);
                        }
                    }
                }
            }

            //畫出所有邊
            for (int i = 0; i < edges.Count; i++)
            {
                Edge e = edges[i];
                if (e.alive)
                {
                    int width = 0;
                    switch (e.attri.type)
                    {
                        case RoadType.Axiom:
                            width = 2;
                            break;
                        case RoadType.HightWay:
                            width = 1;
                            break;
                        default:
                            width = 0;
                            break;
                    }

                    if (e.v[1] > -1)
                    {
                        DrawLine(vertices[e.v[1]], vertices[e.v[0]], e, width);

                        if (e.alive)
                        {
                            ModelGeneratorUtility.GenerateRound(vertices[e.v[0]].x * 1200, vertices[e.v[0]].y * 1200, e.attri.type);
                            ModelGeneratorUtility.GenerateRoad(vertices[e.v[0]].x * 1200, vertices[e.v[0]].y * 1200, vertices[e.v[1]].x * 1200, vertices[e.v[1]].y * 1200, e.attri.type);
                        }
                    }
                }
            }

            //畫出所有端點
            for (int i = 0; i < edges.Count; i++)
            {
                Edge e = edges[i];
                if (e.alive)
                {
                    DrawVertex(vertices[e.v[0]], new Color(0.3f, 0.3f, 1.0f),0);
                    DrawVertex(vertices[e.v[1]], new Color(0.3f, 0.3f, 1.0f),0);
                }
            }

            //畫出關卡點
            if (startPots == null)
                return;

            for (int i = 0; i < startPots.Count; i++)
            {
                Vertex spot = new Vertex(startPots[i].spot.x, startPots[i].spot.y);
                Vertex spot2 = new Vertex(startPots[i].spot2.x, startPots[i].spot2.y);
                Vertex core = new Vertex(startPots[i].core.x, startPots[i].core.y);
                DrawVertex(spot, new Color(0, 1, 1),2);
                DrawVertex(spot2, new Color(0, 1, 1),2);
                DrawVertex(core, new Color(1, 0, 0), 5);
            }
        }

        public void DrawVertex(Vertex p,Color color,int width = 0)
        {
            float dx = (p.x) * _Width;
            float dy = (p.y) * _Height;
            int ry = (int)(dy);
            int rx = (int)(dx);

            for (int j = -width; j <= width; j++)
            {
                for (int i = -width; i <= width; i++)
                {
                    int index = ((ry+j) * _Width + (rx+i));

                    if (index < 0 || index > pixR.Length)
                        continue;

                    pixR[index] = color;
                }
            }

        }

        public void DrawLine(Vertex p2, Vertex p1, Edge e,int width = 0)
        {
            float dx = (p2.x - p1.x) * _Width;
            float dy = (p2.y - p1.y) * _Height;
            float len = Mathf.Sqrt(dx * dx + dy * dy);
            float ddx = dx / len;
            float ddy = dy / len;
            float addx = Mathf.Abs(ddx);
            float addy = Mathf.Abs(ddy);
            float px = p1.x * _Width;
            float py = p1.y * _Height;

            for (int i = 0; i < len; i++)
            {
                for (int j = -width; j <= width; j++)
                {
                    int jddy = (int)(py + ddy * i + 0.5f * j);
                    int jddx = (int)(px + ddx * i - 0.5f * j);
                    int index = (jddy * _Width + jddx);
                    if (index < 0 || index >= pixR.Length)
                        continue;

                    //if (e.attri.type == RoadType.Major)
                    //    pixR[index] = Color.red;
                    //if (e.attri.type == RoadType.Minor)
                    //    pixR[index] = Color.blue;
                    //if (e.extendRoad || e.splitRoad)
                    //    pixR[index] = Color.white;
                    //if (e.attri.isSnapToAdj)
                    //    pixR[index] = Color.yellow;

                    if (e.attri.type == RoadType.Axiom)
                        pixR[index] = new Color(1, 0, 1);
                    else if (e.attri.type == RoadType.HightWay)
                        pixR[index] = Color.green;
                    else
                        pixR[index] = new Color(1.0f, 1.0f, 1.0f);

                    //if (e.extendRoad)
                    //    pixR[index] = Color.yellow;
                    //else if (e.splitRoad)
                    //    pixR[index] = Color.red;

                    //if (e.attri.isSnapToAdj)
                    //    pixR[index] = new Color(0, 1, 1);

                    //if (!e.alive)
                    //    pixR[index] = Color.red;
                }
            }

        }


#if WMTHEIGHT_MAP
        public float elevation(float uvx,float uvy)
        {

            return 0.15f;
        }
#endif

        //edges ++ 
        public Edge InsertEdge(int i0,int i1, Edge pe, bool isSnapToAdj)
        {
            Edge ne = new Edge(pe);
            ne.v[0] = i0;
            ne.v[1] = i1;
            ne.attri.isSnapToAdj = isSnapToAdj;

            AddEdge(ne);
            return ne;
        }


        //檢測新生點越界
        public bool CheckBound(float x, float y)
        {
            if (x < minBound || x > maxBound || y < minBound || y > maxBound)
                return false;
            return true;
        }

        //檢測兩條邊的夾角dot product,v0作爲檢測原點
        public bool CheckLegality01(Vertex v0, Vertex v1,float dotThreshold)
        {
            Vertex v10 = (v1 - v0).Normalized2d();

            for (int i = 0; i < v0.adjacent.Count; i++)
            {
                Vertex v2 = GetVertex(v0.adjacent[i]);
                Vertex v20 = (v2 - v0).Normalized2d();

                float dot = v20.x * v10.x + v20.y * v10.y;

                if (dot > dotThreshold)
                    return false;
            }

            return true;
        }


        //檢查v0十字路口的繁忙程度
        public float CheckInterSectionBusyDegree(Vertex v0, Vertex v1 = null)
        {
            float busyDegree = 0;

            if (v0.adjacent.Count >= 3)
            {
                busyDegree += (v0.adjacent.Count - 2) * COST_INTERSECIONT_OVERLOARD;
            }
            else
            {
                busyDegree += (3 - v0.adjacent.Count) * COST_INTERSECIONT_UNDERLOAD;
            }

            return busyDegree;
        }


        //1級約束
        public bool LocalConstraint(Edge pe)
        {
            float cost = 0.0f;

            Vertex v0, v1;
            if (pe.v[0] > -1)
                v0 = GetVertex(pe.v[0]);
            else
            {
                v0 = new Vertex(pe.newVertices[0].x, pe.newVertices[0].y);
            }

            if (pe.v[1] > -1)
                v1 = GetVertex(pe.v[1]);
            else
            {
                v1 = new Vertex(pe.newVertices[1].x, pe.newVertices[1].y);
            }


            if (pe.v[0] < 0 || pe.v[1] < 0)
            {
                float prob = 0;
                if (pe.attri.type <= RoadType.HightWay)
                    prob = 0.5f;
                else
                    prob = 1.0f;

                if (GetRandom() < prob)
                    cost += ColliderFindIntersection(v0, v1, pe);
            }

            if (CheckLegality01(v0, v1, INTERSECIONT_DOT_01) && CheckBound(v1.x, v1.y))
            {
                //十字路口A繁忙度檢測
                cost += CheckInterSectionBusyDegree(v0);

                return (cost < jitter(COST_THRESHOLD, COST_THRESHOLD_JITTER));
            }
            else
                return false;
        }

        //2級約束 + 生成結果邊
        public bool AcceptProposal(Edge pe,out int i0,out int i1)
        {
            bool needSplitExsitedEdgeFrom1to2 = false;//將被强行變成十字路口的邊從一條邊强行截斷成兩條邊
            bool isSnapToAdjacentExistedVector = false;//指新端點被合并到最近的已存在路口
            bool isSpEx = (pe.splitRoad || pe.extendRoad);//指新端點發生了 延長/截斷 到最近的路段的操作

            if (pe.v[0] > -1)
                i0 = pe.v[0];
            else
            {
                i0 = GetVertexCount();
                Vertex nV0 = new Vertex(pe.newVertices[0].x, pe.newVertices[0].y);
                AddVertex(nV0);
                nV0.type = pe.attri.type;
                pe.v[0] = i0;
            }

            if (pe.v[1] > -1)
                i1 = pe.v[1];
            else
            {
                //如果端點1不存在，則根據規則生成新端點
                i1 = GetVertexCount();
                Vertex nV1 = new Vertex(pe.newVertices[1].x, pe.newVertices[1].y);

                int TIMES = 10;
                switch (pe.attri.type)
                {
                    case RoadType.Axiom:
                        TIMES = INTERSECTION_SCAN_WIDTH_A;
                        break;
                    case RoadType.HightWay:
                        TIMES = INTERSECTION_SCAN_WIDTH_A;
                        break;
                    case RoadType.Major:
                        TIMES = INTERSECTION_SCAN_WIDTH_B;
                        break; 
                    case RoadType.Minor:
                        TIMES = INTERSECTION_SCAN_WIDTH_C;
                        break;
                }

                if (false && isSpEx)//&& isSpEx如果對目標edge裁剪或者延長到某條交綫
                {
                    //AddVertex(nV1);
                    //nV1.type = pe.attri.type;
                }
                else
                {
                    //如果是截斷延長點，縮小查找距離，爲了保留更多十字路口
                    if (isSpEx && TIMES > 5)
                        TIMES = TIMES / 2 + 1;

                    //查找端點1附近的鄰近端點
                    int minDisNeighbor = ColliderFindNearby(nV1, i0, TIMES);
                    if (minDisNeighbor == -1)
                    {
                        //如果沒有碰撞，則加入結果
                        AddVertex(nV1);
                        nV1.type = pe.attri.type;
                        pe.v[1] = i1;
                        if (isSpEx)
                            needSplitExsitedEdgeFrom1to2 = true;
                    }
                    else
                    {
                        i1 = minDisNeighbor;
                        pe.v[1] = i1;
                        isSnapToAdjacentExistedVector = true;
                    }
                }
            }

            //將被强行變成十字路口的邊從一條邊强行截斷成兩條邊
            if (needSplitExsitedEdgeFrom1to2)
            {
                Edge adsorbEdge = GetEdge(pe.spexTarget);//被截斷邊
                Edge eNew1 = new Edge(adsorbEdge);
                Edge eNew2 = new Edge(adsorbEdge);
                eNew1.beSplitedL = true;
                eNew2.beSplitedR = true;
                eNew1.v[0] = adsorbEdge.v[0];
                eNew1.v[1] = i1;
                eNew2.v[0] = i1;
                eNew2.v[1] = adsorbEdge.v[1];

                GetVertex(i1).AddAdjacent(adsorbEdge.v[0]);
                GetVertex(i1).AddAdjacent(adsorbEdge.v[1]);

                if (CheckLegality01(GetVertex(i1), GetVertex(pe.v[0]), INTERSECIONT_DOT_10))
                {
                    //將1條被截斷邊變成2條新邊
                    AddEdge(eNew1);
                    AddEdge(eNew2);
                    RemoveEdge(adsorbEdge);
                }
                else
                {
                    //撤銷截斷操作
                    //RemoveVertex(GetVertex(i1));
                    return false;
                }
            }

            //十字路口B繁忙度檢測
            float cost2 = CheckInterSectionBusyDegree(GetVertex(i1));
            if (cost2 > jitter(0.4f, 0.3f))
                return false;

            //如果通過所有處理，則加入當前處理邊到結果表
            InsertEdge(i0, i1, pe, isSnapToAdjacentExistedVector);

            return true;
        }


        //生成岔路
        public void GetGridPoint(float angle, Vertex src, float j, int i, out float x, out float y, out float z,float MAJOR,float MINOR, float JITTER)
        {
            float[] dA = { -1.57f, 0.0f, 1.57f };
            float lJ = jitter(0, JITTER);
            float l1 = MAJOR + lJ;
            float l2 = MINOR + lJ;

            x = src.x + l1 * Mathf.Cos(angle + dA[i]) * Mathf.Cos(j) - l2 * Mathf.Sin(angle + dA[i]) * Mathf.Sin(j);//cos(A+B)
            y = src.y + l1 * Mathf.Cos(angle + dA[i]) * Mathf.Sin(j) + l2 * Mathf.Sin(angle + dA[i]) * Mathf.Cos(j);//sin(A+B)
            z = 0;
        }

        //生成主幹道
        public float GetHighWayPoint(float angle, Vertex src,out float x,out float y,out float z,float LENGTH,float JITTER,float ANGLE_JITTER)
        {
            float currMinScore = float.MaxValue;
            float currMinAngle = angle;
            float length = jitter(LENGTH, JITTER);
            z = 0;
#if WMTHEIGHT_MAP
            for (int i = 0; i < NUM_HIGHWAY_PROBES; i++)
            {
                float probeAngle = ((ANGLE_HIGHWAY_PROBES * i) / NUM_HIGHWAY_PROBES) - ANGLE_HIGHWAY_PROBES * i + angle;
                float dx = src.x + length * Mathf.Cos(probeAngle);
                float dy = src.y + length * Mathf.Sin(probeAngle);

                float samp = elevation(dx, dy);
                float deltaZ = Mathf.Abs(samp - src.z);
                if (deltaZ < currMinScore)
                {
                    currMinScore = deltaZ;
                    currMinAngle = probeAngle;
                    z = samp;
                }
            }
#endif

            float terrainAngle = jitter(currMinAngle, ANGLE_JITTER);
            float w = jitter(WEIGHT_TERRAIN_CONTOUR, WEIGHT_TERRAIN_CONTOUR_JITTER);
            float fAngle = w * terrainAngle + (1 - w) * angle;
            x = src.x + length * Mathf.Cos(fAngle);
            y = src.y + length * Mathf.Sin(fAngle);

            return fAngle;
        }


        public void GlobleGoals(float t,Edge pEdge, int i0,int i1)
        {
            Vertex v0 = GetVertex(i0);//端點0
            Vertex v1 = GetVertex(i1);//端點1
            if (v1.adjacent.Count > 1)
            {
                float EXIT_PROB = 0.0f;
                switch (pEdge.attri.type)
                {
                    case RoadType.HightWay:
                        EXIT_PROB = 0.0f;
                        break;
                    case RoadType.Major:
                        EXIT_PROB = 0.0f;
                        break;
                    default:
                        EXIT_PROB = 0.0f;
                        break;
                }

                if (GetRandom() > EXIT_PROB)
                    return;
            }

            //優先級
            float angle = pEdge.attri.angle;//幹道方向
            float axis = pEdge.attri.axis;
    
            RoadType type = pEdge.attri.type;

            //角度隨機偏移抖動
            float j = 0;
            float PROBABILITY;
            float AMOUNT;

            switch (type)
            {
                case RoadType.Axiom:
                    PROBABILITY = GRID_DEVIATION_PROBABILITY_0;
                    AMOUNT = GRID_DEVIATION_AMOUNT_0;
                    break;
                case RoadType.HightWay:
                    PROBABILITY = GRID_DEVIATION_PROBABILITY_0;
                    AMOUNT = GRID_DEVIATION_AMOUNT_0;
                    break;
                case RoadType.Major:
                    PROBABILITY = GRID_DEVIATION_PROBABILITY_1;
                    AMOUNT = GRID_DEVIATION_AMOUNT_1;
                    break;
                case RoadType.Minor:
                    PROBABILITY = GRID_DEVIATION_PROBABILITY_2;
                    AMOUNT = GRID_DEVIATION_AMOUNT_2;
                    break;
                default:
                    PROBABILITY = 0.1f;
                    AMOUNT = 1.46f;
                    break;
            }

            if (GetRandom() < PROBABILITY)
            {
                j = jitter(0, AMOUNT);
                j = j * j * j;
            }

            float rho = 7.75f;
            float x, y, z;
            float delay;
            switch (type)
            {
                case RoadType.Axiom:

                    float[] a = {angle + 3.14f, angle};
                    int[] vi = {i0, i1};
                    Vertex[] positions = {new Vertex(v0.x, v0.y, v0.z),
                        new Vertex(v1.x, v1.y, v1.z) };
                    delay = (t + EVAL_DELAY_HIGHWAY) / rho;
                    for (int i = 0; i < 2; i++)
                    {
                        GetGridPoint(a[i], positions[i], 0, 1, out x, out y, out z, ROAD_LENGTH_MAJOR_0, ROAD_LENGTH_MINOR_0, ROAD_LENGTH_JITTER_0);

                        Edge newEdge 
                            = new Edge((int)delay, RoadType.HightWay,
                            a[i], a[i], vi[i], x, y);

                        procesedEdges.Push(newEdge);
                    }

                    break;
                case RoadType.HightWay:

                    float fAngle = GetHighWayPoint(angle, v1, out x, out y, out z, ROAD_LENGTH_HIGHWAY_0, ROAD_LENGTH_JITTER_0, HIGHWAY_ANGLE_JITTER_0);
                    delay = (t + EVAL_DELAY_HIGHWAY) / rho;
                    Edge newHighway = new Edge((int)delay, RoadType.HightWay, fAngle, fAngle, i1, x, y);
                    procesedEdges.Push(newHighway);

                    //side roads
                    float[] aHs = { -1.57f, 1.57f };
                    for (int i = 0; i < 2; i++)
                    {
                        GetGridPoint(angle, v1, j, i == 0 ? 0 : 2, out x, out y, out z, ROAD_LENGTH_MAJOR_0, ROAD_LENGTH_MINOR_0, ROAD_LENGTH_JITTER_0);
                        Edge newSideWay;
                        if (GetRandom() > HIGHWAY_PROMOTION_PROBABILITY)
                        {
                            delay = (t+EVAL_DELAY_MAJOR)/rho;
                            newSideWay = new Edge((int)delay, RoadType.Major, angle + aHs[i] + j, axis + j, i1, x, y);
                            procesedEdges.Push(newSideWay);
                        }
                        else
                        {
                            delay = (t + EVAL_DELAY_HIGHWAY) / rho;
                            newSideWay = new Edge((int)delay, RoadType.HightWay, angle + aHs[i] + j, axis + j, i1, x, y);
                            procesedEdges.Push(newSideWay);
                        }
                    }
                    break;

                case RoadType.Major:
                    float[] aMj = { -1.57f, 0, 1.57f };

                    for (int i = 0; i < 3; i++)
                    {
                        Edge newMajorMinor;
                        if (i == 1)
                        {
                            float fMjAngle = GetHighWayPoint(angle, v1, out x, out y, out z, ROAD_LENGTH_HIGHWAY_1, ROAD_LENGTH_JITTER_1, HIGHWAY_ANGLE_JITTER_1);
                            delay = (t + EVAL_DELAY_MAJOR) / rho;
                            newMajorMinor = new Edge((int)delay, RoadType.Major, fMjAngle, fMjAngle, i1, x, y);
                        }
                        else
                        {
                            GetGridPoint(angle, v1, j, i, out x, out y, out z, ROAD_LENGTH_MAJOR_2, ROAD_LENGTH_MINOR_2, ROAD_LENGTH_JITTER_2);
                            delay = (t + EVAL_DELAY_MINOR) / rho;

                            newMajorMinor = new Edge((int)delay, RoadType.Minor, angle + aMj[i] + j, axis + j, i1, x, y);
                        }

                        procesedEdges.Push(newMajorMinor);

                    }

                    break;

                case RoadType.Minor:
                    float[] aMi = { -1.57f, 0, 1.57f };

                    for (int i = 0; i < 3; i++)
                    {
                        Edge newMinorMajor;
                        if (i == 1)
                        {
                            GetGridPoint(angle, v1, j, i, out x, out y, out z, ROAD_LENGTH_MAJOR_2, ROAD_LENGTH_MINOR_2, ROAD_LENGTH_JITTER_2);
                            delay = (t + EVAL_DELAY_MINOR) / rho;

                            newMinorMajor = new Edge((int)delay, RoadType.Minor, angle + aMi[i] + j, axis + j, i1, x, y);
                        }
                        else if (GetRandom() < SIDE_ROAD_PROBABILITY)
                        {
                            GetGridPoint(angle, v1, j, i, out x, out y, out z, ROAD_LENGTH_MAJOR_1, ROAD_LENGTH_MINOR_1, ROAD_LENGTH_JITTER_1);
                            delay = (t + EVAL_DELAY_MAJOR) / rho;

                            newMinorMajor = new Edge((int)delay, RoadType.Major, angle + aMi[i] + j, axis + j, i1, x, y);
                        }
                        else
                            continue;

                        procesedEdges.Push(newMinorMajor);
                    }

                    break;

                default:
                    break;
            }
        }

        private bool ConfigMapping(string name, float value)
        {
            float oldValue = 0;
            switch (name)
            {
                case "STARTROADWIDTH":
                    STARTROADWIDTH = (int)value;
                    break;
                case "START_JITTER_LENGTH":
                    START_JITTER_LENGTH = (int)value;
                    break;
                case "INTERSECTION_SCAN_WIDTH_A":
                    INTERSECTION_SCAN_WIDTH_A = (int)value;
                    break;
                case "INTERSECTION_SCAN_WIDTH_B":
                    INTERSECTION_SCAN_WIDTH_B = (int)value;
                    break;
                case "INTERSECTION_SCAN_WIDTH_C":
                    INTERSECTION_SCAN_WIDTH_C = (int)value;
                    break;
                case "ROAD_LENGTH_HIGHWAY_0":
                    ROAD_LENGTH_HIGHWAY_0 = value;
                    break;
                case "ROAD_LENGTH_MAJOR_0":
                    ROAD_LENGTH_MAJOR_0 = value;
                    break;
                case "ROAD_LENGTH_MINOR_0":
                    ROAD_LENGTH_MINOR_0 = value;
                    break;
                case "ROAD_LENGTH_JITTER_0":
                    ROAD_LENGTH_JITTER_0 = value;
                    break;
                case "HIGHWAY_ANGLE_JITTER_0":
                    HIGHWAY_ANGLE_JITTER_0 = value;
                    break;
                case "ROAD_LENGTH_HIGHWAY_1":
                    ROAD_LENGTH_HIGHWAY_1 = value;
                    break;
                case "ROAD_LENGTH_MAJOR_1":
                    ROAD_LENGTH_MAJOR_1 = value;
                    break;
                case "ROAD_LENGTH_MINOR_1":
                    ROAD_LENGTH_MINOR_1 = value;
                    break;
                case "ROAD_LENGTH_JITTER_1":
                    ROAD_LENGTH_JITTER_1 = value;
                    break;
                case "HIGHWAY_ANGLE_JITTER_1":
                    HIGHWAY_ANGLE_JITTER_1 = value;
                    break;
                case "ROAD_LENGTH_MAJOR_2":
                    ROAD_LENGTH_MAJOR_2 = value;
                    break;
                case "ROAD_LENGTH_MINOR_2":
                    ROAD_LENGTH_MINOR_2 = value;
                    break;
                case "ROAD_LENGTH_JITTER_2":
                    ROAD_LENGTH_JITTER_2 = value;
                    break;
                case "HIGHWAY_PROMOTION_PROBABILITY":
                    HIGHWAY_PROMOTION_PROBABILITY = value;
                    break;
                case "SIDE_ROAD_PROBABILITY":
                    SIDE_ROAD_PROBABILITY = value;
                    break;
                case "GRID_DEVIATION_PROBABILITY_0":
                    GRID_DEVIATION_PROBABILITY_0 = value;
                    break;
                case "GRID_DEVIATION_AMOUNT_0":
                    GRID_DEVIATION_AMOUNT_0 = value;
                    break;
                case "GRID_DEVIATION_PROBABILITY_1":
                    GRID_DEVIATION_PROBABILITY_1 = value;
                    break;
                case "GRID_DEVIATION_AMOUNT_1":
                    GRID_DEVIATION_AMOUNT_1 = value;
                    break;
                case "GRID_DEVIATION_PROBABILITY_2":
                    GRID_DEVIATION_PROBABILITY_2 = value;
                    break;
                case "GRID_DEVIATION_AMOUNT_2":
                    GRID_DEVIATION_AMOUNT_2 = value;
                    break;
                case "WEIGHT_TERRAIN_CONTOUR":
                    WEIGHT_TERRAIN_CONTOUR = value;
                    break;
                case "WEIGHT_TERRAIN_CONTOUR_JITTER":
                    WEIGHT_TERRAIN_CONTOUR_JITTER = value;
                    break;
                case "COST_THRESHOLD":
                    COST_THRESHOLD = value;
                    break;
                case "COST_THRESHOLD_JITTER":
                    COST_THRESHOLD_JITTER = value;
                    break;
                case "COST_INTERSECIONT_OVERLOARD":
                    COST_INTERSECIONT_OVERLOARD = value;
                    break;
                case "COST_INTERSECIONT_UNDERLOAD":
                    COST_INTERSECIONT_UNDERLOAD = value;
                    break;
                case "INTERSECIONT_DOT_01":
                    INTERSECIONT_DOT_01 = value;
                    break;
                case "INTERSECIONT_DOT_10":
                    INTERSECIONT_DOT_10 = value;
                    break;

            }
            return true;
        }

    }
}